# coding=utf8

from cefpython3 import cefpython
import os,sys
import pygtk
pygtk.require('2.0')
import gtk
import gobject


#
# Globals
#
g_applicationSettings = {}
g_browserSettings = {}
g_commandLineSwitches = {}

def GetApplicationPath(file=None):
    import re, os, platform
    # On Windows after downloading file and calling Browser.GoForward(),
    # current working directory is set to %UserProfile%.
    # Calling os.path.dirname(os.path.realpath(__file__))
    # returns for eg. "C:\Users\user\Downloads". A solution
    # is to cache path on first call.
    if not hasattr(GetApplicationPath, "dir"):
        if hasattr(sys, "frozen"):
            dir = os.path.dirname(sys.executable)
        elif "__file__" in globals():
            dir = os.path.dirname(os.path.realpath(__file__))
        else:
            dir = os.getcwd()
        GetApplicationPath.dir = dir
    # If file is None return current directory without trailing slash.
    if file is None:
        file = ""
    # Only when relative path.
    if not file.startswith("/") and not file.startswith("\\") and (
            not re.search(r"^[\w-]+:", file)):
        path = GetApplicationPath.dir + os.sep + file
        if platform.system() == "Windows":
            path = re.sub(r"[/\\]+", re.escape(os.sep), path)
        path = re.sub(r"[/\\]+$", "", path)
        return path
    return str(file)

def ExceptHook(excType, excValue, traceObject):
    import traceback, os, time, codecs
    # This hook does the following: in case of exception write it to
    # the "error.log" file, display it to the console, shutdown CEF
    # and exit application immediately by ignoring "finally" (_exit()).
    errorMsg = "\n".join(traceback.format_exception(excType, excValue,
            traceObject))
    errorFile = GetApplicationPath("error.log")
    try:
        appEncoding = cefpython.g_applicationSettings["string_encoding"]
    except:
        appEncoding = "utf-8"
    if type(errorMsg) == bytes:
        errorMsg = errorMsg.decode(encoding=appEncoding, errors="replace")
    try:
        with codecs.open(errorFile, mode="a", encoding=appEncoding) as fp:
            fp.write("\n[%s] %s\n" % (
                    time.strftime("%Y-%m-%d %H:%M:%S"), errorMsg))
    except:
        print("[pygtk_.py]: WARNING: failed writing to error file: %s" % (
                errorFile))
    # Convert error message to ascii before printing, otherwise
    # you may get error like this:
    # | UnicodeEncodeError: 'charmap' codec can't encode characters
    errorMsg = errorMsg.encode("ascii", errors="replace")
    errorMsg = errorMsg.decode("ascii", errors="replace")
    print("\n"+errorMsg+"\n")
    cefpython.QuitMessageLoop()
    cefpython.Shutdown()
    os._exit(1)

class CookieVisitor:

    def __init__(self):
        import os.path
        if os.path.exists("./qixin.cookie"):
            os.remove("./qixin.cookie")

        self.__cookie_cb__ = None

    def Visit(self, cookie, count, total, deleteCookie):
        if count == 0:
            print("\n[wxpython.py] CookieVisitor.Visit(): total cookies: %s"\
                    % total)
        print("\n[wxpython.py] CookieVisitor.Visit(): cookie:")
        cookieDict = cookie.Get()
        print("    "+str(cookieDict))
        print("\n[wxpython.py] Write cookie to file")
        self.__save_file = open("./qixin.cookie", "a+")
        self.__save_file.write(str(cookieDict))
        self.__save_file.write("\r\n")
        self.__save_file.close()
        # True to continue visiting cookiesa
        if self.__cookie_cb__:
            self.__cookie_cb__()
        return True

    def SetOnCookieStoreCallback(self, cb):
        self.__cookie_cb__ = cb

class ClientHandler:
    mainBrowser = None # May be None for global client callbacks.

    def __init__(self):
        pass

    def __VisitUrlCookies(self):
        # Need to keep the reference alive.
        self.cookieVisitor = CookieVisitor()
        self.cookieVisitor.SetOnCookieStoreCallback(
            self.__OnCookieStored
        )
        cookieManager = self.mainBrowser.GetUserData("cookieManager")
        if not cookieManager:
            print("\n[wxpython.py] Cookie manager not yet created! Visit"\
                    " the cookietester website first and create some cookies")
            return
        cookieManager.VisitAllCookies(
            self.cookieVisitor)

    def __OnCookieStored(self):
        if self.mainBrowser:
            self.mainBrowser.CloseBrowser(True)

    # -------------------------------------------------------------------------
    # RequestHandler
    # -------------------------------------------------------------------------
    def GetCookieManager(self, browser, mainUrl):
        # Create unique cookie manager for each browser.
        # You must set the "unique_request_context_per_browser"
        # application setting to True for the cookie manager
        # to work.
        # Return None to have one global cookie manager for
        # all CEF browsers.
        if not browser:
            # The browser param may be empty in some exceptional
            # case, see docs.
            return None
        cookieManager = browser.GetUserData("cookieManager")
        if cookieManager:
            return cookieManager
        else:
            print("[wxpython.py] RequestHandler::GetCookieManager():"\
                    " created cookie manager")
            cookieManager = cefpython.CookieManager.CreateManager("")
            browser.SetUserData("cookieManager", cookieManager)
            return cookieManager

    def _OnCertificateError(self, certError, requestUrl, callback):
        callback.Continue(True)
        return True

    def _OnBeforePluginLoad(self, browser, mimeType, pluginUrl, topOriginUrl, info):
        return False

    # -------------------------------------------------------------------------
    # LifespanHandler
    # -------------------------------------------------------------------------
    def _OnAfterCreated(self, browser):
        # This is a global callback set using SetGlobalClientCallback().
        print("[wxpython.py] LifespanHandler::_OnAfterCreated()")
        print("    browserId=%s" % browser.GetIdentifier())

    def DoClose(self, browser):
        print("[wxpython.py] LifespanHandler::DoClose()")
        print("    browserId=%s" % browser.GetIdentifier())

    def OnBeforeClose(self, browser):
        print("[wxpython.py] LifespanHandler::OnBeforeClose")
        print("    browserId=%s" % browser.GetIdentifier())

    # -------------------------------------------------------------------------
    # LoadHandler
    # -------------------------------------------------------------------------
    def OnLoadEnd(self, browser, frame, httpStatusCode):
        print("[wxpython.py] LoadHandler::OnLoadEnd()")
        print("    frame url = %s" % frame.GetUrl()[:100])
        # For file:// urls the status code = 0
        print("    http status code = %s" % httpStatusCode)
        # Tests for the Browser object methods
        render_url = frame.GetUrl()[:100]
        if httpStatusCode == 200 and render_url == "http://www.qixin.com/":
            self.__VisitUrlCookies()

class GtkMainForm:
    mainWindow = None
    container = None
    browser = None
    exiting = None
    clientHandler = None


    def __init__(self):
        gobject.timeout_add(10, self.OnTimer)

        self.mainWindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.mainWindow.connect('destroy', self.OnExit)
        self.mainWindow.set_size_request(width=1300, height=600)
        self.mainWindow.set_title('S-spider Login tool')
        self.mainWindow.realize()

        self.container = gtk.DrawingArea()
        self.container.set_property('can-focus', True)
        self.container.connect('size-allocate', self.OnSize)
        self.container.show()

        table = gtk.Table(3, 1, homogeneous=False)
        self.mainWindow.add(table)
        table.attach(self.container, 0, 1, 2, 3)
        table.show()

        # Global client callbacks must be set before browser is created.
        self.clientHandler = ClientHandler()
        cefpython.SetGlobalClientCallback("OnCertificateError",
                self.clientHandler._OnCertificateError)
        cefpython.SetGlobalClientCallback("OnBeforePluginLoad",
                self.clientHandler._OnBeforePluginLoad)
        cefpython.SetGlobalClientCallback("OnAfterCreated",
                self.clientHandler._OnAfterCreated)

        windowID = self.container.get_window().handle
        windowInfo = cefpython.WindowInfo()
        windowInfo.SetAsChild(windowID)

        appPath = "http://www.qixin.com/login"
        self.browser = cefpython.CreateBrowserSync(windowInfo,
                browserSettings=g_browserSettings,
                navigateUrl=appPath)

        self.clientHandler.mainBrowser = self.browser
        self.browser.SetClientHandler(self.clientHandler)

        self.mainWindow.show()
        self.mainWindow.get_window().focus()

    def OnWidgetClick(self, widget, data):
        self.mainWindow.get_window().focus()

    def OnTimer(self):
        if self.exiting:
            return False
        cefpython.MessageLoopWork()
        return True

    def OnSize(self, widget, sizeAlloc):
        cefpython.WindowUtils.OnSize(self.container.get_window().handle, 0, 0, 0)

    def OnClose(self, event):
        print "Gtk Main Form is closing..."

    def OnExit(self):
        self.exiting = True
        gtk.main_quit()

def readCookie():
    pass

if __name__ == '__main__':

    sys.excepthook = ExceptHook

    g_applicationSettings = {
        # Disk cache
        # "cache_path": "webcache/",

        # CEF Python debug messages in console and in log_file
        "debug": True,
        # Set it to LOGSEVERITY_VERBOSE for more details
        "log_severity": cefpython.LOGSEVERITY_INFO,

        # These directories must be set on Linux
        "locales_dir_path": cefpython.GetModuleDirectory()+"/locales",
        "resources_dir_path": cefpython.GetModuleDirectory(),
        # The "subprocess" executable that launches the Renderer
        # and GPU processes among others. You may rename that
        # executable if you like.
        "browser_subprocess_path": "%s/%s" % (
            cefpython.GetModuleDirectory(), "subprocess"),

        # This option is required for the GetCookieManager callback
        # to work. It affects renderer processes, when this option
        # is set to True. It will force a separate renderer process
        # for each browser created using CreateBrowserSync.
        "unique_request_context_per_browser": True,
        # Downloads are handled automatically. A default SaveAs file
        # dialog provided by OS will be displayed.

        "downloads_enabled": True,
        # Remote debugging port, required for Developer Tools support.
        # A value of 0 will generate a random port. To disable devtools
        # support set it to -1.
        "remote_debugging_port": 0,
        # Mouse context menu
        "context_menu": {
            "enabled": True,
            "navigation": True, # Back, Forward, Reload
            "print": True,
            "view_source": True,
            "external_browser": True, # Open in external browser
            "devtools": True, # Developer Tools
        },

        # See also OnCertificateError which allows you to ignore
        # certificate errors for specific websites.
        "ignore_certificate_errors": True,
    }

    g_commandLineSwitches = {}

    cefpython.Initialize(g_applicationSettings, g_commandLineSwitches)
    gobject.threads_init()
    GtkMainForm()
    gtk.main()
    cefpython.Shutdown()